package 多线程;

public class 线程组ThreadGroup {

}

线程组介绍
线程组(ThreadGroup)简单来说就是一个线程集合。线程组的出现是为了更方便地管理线程。
线程组的作用是，可以批量的管理线程或线程组对象，有有效地对线程或线程组对象进行组织。
线程组是父子结构的，一个线程组可以集成其他线程组，同时也可以拥有其他子线程组。从结构上看，线程组是一个树形结构，每个线程都隶属于一个线程组，线程组又有父线程组，
这样追溯下去，可以追溯到一个根线程组——System线程组。


下面介绍一下线程组树的结构：

JVM创建的system线程组是用来处理JVM的系统任务的线程组，例如对象的销毁等。
system线程组的直接子线程组是main线程组，这个线程组至少包含一个main线程，用于执行main方法。
main线程组的子线程组就是应用程序创建的线程组。
你可以在main方法中看到JVM创建的system线程组和main线程组:

public static void main(String[] args) {
      ThreadGroup mainThreadGroup=Thread.currentThread().getThreadGroup();
      ThreadGroup systenThreadGroup=mainThreadGroup.getParent();
      System.out.println("systenThreadGroup name = "+systenThreadGroup.getName());
      System.out.println("mainThreadGroup name = "+mainThreadGroup.getName());
  }
console输出：

systenThreadGroup name = system
mainThreadGroup name = main
一个线程可以访问其所属线程组的信息，但不能访问其所属线程组的父线程组或者其他线程组的信息。

线程组的构造
java.lang.ThreadGroup提供了两个构造函数：


下面演示一下这两个构造函数的用法：

public static void main(String[] args) {
    ThreadGroup subThreadGroup1 = new ThreadGroup("subThreadGroup1");
    ThreadGroup subThreadGroup2 = new ThreadGroup(subThreadGroup1, "subThreadGroup2");
    System.out.println("subThreadGroup1 parent name = " + subThreadGroup1.getParent().getName());
    System.out.println("subThreadGroup2 parent name = " + subThreadGroup2.getParent().getName());
}
console输出：

subThreadGroup1 parent name = main
subThreadGroup2 parent name = subThreadGroup1
ThreadGroup方法介绍
ThreadGroup提供了很多有用的方法，下面提供了这些方法的简要介绍，以及部分方法的使用示例。

ThreadGroup()
ThreadGroup(String)
ThreadGroup(ThreadGroup, String)
ThreadGroup(Void, ThreadGroup, String)
checkParentAccess(ThreadGroup)
getName()
getParent()
getMaxPriority()
isDaemon()
isDestroyed()
setDaemon(boolean)
setMaxPriority(int)
parentOf(ThreadGroup)
checkAccess()
activeCount()
enumerate(Thread[])
enumerate(Thread[], boolean)
enumerate(Thread[], int, boolean)
activeGroupCount()
enumerate(ThreadGroup[])
enumerate(ThreadGroup[], boolean)
enumerate(ThreadGroup[], int, boolean)
stop()
interrupt()
suspend()
stopOrSuspend(boolean)
resume()
destroy()
add(ThreadGroup)
remove(ThreadGroup)
addUnstarted()
add(Thread)
threadStartFailed(Thread)
threadTerminated(Thread)
remove(Thread)
list()
list(PrintStream, int)
uncaughtException(Thread, Throwable)
allowThreadSuspension(boolean)
toString()
有两个构造方法：

指定创建此线程组的线程组为父线程组：ThreadGroup(String name)
指定创建特定的线程组为父线程组:ThreadGroup(ThreadGroup parent, String name)

API作用                            方法名称                  说明
评估当前活跃的线程数	                activeCount()	
评估当前活跃的子线程组数                activeGroupCount()	
判断当前线程是否有权限更改线程组的状态     checkAccess()	
销毁此线程组                         destroy()              此线程组如果还有活跃的线程或者已经被销毁，会抛出异常
拷贝线程组的线程到一个数组中             enumerate(Thread[] list)	
拷贝时赋予一个true，代表递归本线程组和子线程组，如果为false，则只拿本线程组的	enumerate(Thread[] list, boolean recurse)	
会打断线程组内全部的线程                interrupt()            包括子线程组的线程都会中断
设置线程组内全部的线程为守护线程          setDaemon(boolean daemon)  跟Thread方法不同，设置完成后，线程组在其最后一个线程死亡后，
																					会自动销毁该线程组，主要做自动回收处理



查看线程组信息
下面演示了查看当前线程组的信息。

public static void list(){
        ThreadGroup tg = new ThreadGroup ("subgroup 1");
        Thread t1 = new Thread (tg, "thread 1");
        Thread t2 = new Thread (tg, "thread 2");
        Thread t3 = new Thread (tg, "thread 3");
        tg = new ThreadGroup ("subgroup 2");
        Thread t4 = new Thread (tg, "my thread");
        tg = Thread.currentThread ().getThreadGroup ();
        int agc = tg.activeGroupCount ();
        System.out.println ("Active thread groups in " + tg.getName () + " thread group: " + agc);
        tg.list ();
}
输出如下：

Active thread groups in main thread group: 2
java.lang.ThreadGroup[name=main,maxpri=10]
    Thread[main,5,main]
    java.lang.ThreadGroup[name=subgroup 1,maxpri=10]
    java.lang.ThreadGroup[name=subgroup 2,maxpri=10]
终止线程组中的所有线程
一个线程应由其他线程来强制中断或停止，而是应该由线程自己自行停止。

因此 Thread.currentThread().stop(), Thread.currentThread().suspend(), Thread.currentThread().resume() 都已经被废弃了。

interrupt() 方法的作用是通知线程应该中断了，具体到底中断还是继续运行，由被通知的线程处理。

public class ThreadGroupExampleInterrupt {

    public static void main(String[] args) {

        // Start two threads
        MyThread mt = new MyThread();
        mt.setName("A");
        mt.start();
        mt = new MyThread();
        mt.setName("B");
        mt.start();

        // Wait 2 seconds
        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Interrupt all methods in the same thread group as the main thread
        Thread.currentThread().getThreadGroup().interrupt();

    }

    //一个启动以后进入等待，直到被interrupt的线程
    static class MyThread extends Thread {
        public void run() {
            synchronized ("A") {
                System.out.println(getName() + " about to wait.");
                try {
                    "A".wait();
                } catch (InterruptedException e) {
                    System.out.println(getName() + " interrupted.");
                }
                System.out.println(getName() + " terminating.");
            }
        }
    }
}
执行main方法输出：

A about to wait.
B about to wait.
A interrupted.
A terminating.
B interrupted.
B terminating.


1。 Java使用ThreadGroup来表示线程组，它可以对一批线程进行分类管理，Java允许程序直接对线程组进行控制。

2。 一旦某个线程加入了指定线程组之后，该线程将一直属于该线程组，直到该线程死亡，线程运行中途不能改变它所属的线程组。

3。 Thread类提供了如下几个构造器来设置新创建的线程属于哪个线程组：

Thread(ThreadGroup group, Runnable target)：以target的run方法作为线程执行体创建新线程，属于group线程组。

Thread(ThreadGroup group, Runnable target, String name)：以target的run方法作为线程执行体创建新线程，该线程属于group线程组，且线程名为name。

Thread(ThreadGroup group, String name)：创建新线程，新线程名为name，属于group线程组。

4。 Thread类没有提供setThreadGroup的方法来改变线程所属的线程组，但提供了一个getThreadGroup()方法来返回该线程所属的线程组，getThreadGroup()方法的返回值是ThreadGroup对象，表示一个线程组。

5。 ThreadGroup类有如下两个简单的构造器来创建实例。

ThreadGroup(String name)：以指定线程组名字来创建新的线程组。

ThreadGroup(ThreadGroup parent, String name)：以指定的名字、指定的父线程组创建一个新线程组。

二 实战

1 代码

class MyThread extends Thread{
     // 提供指定线程名的构造器
     public MyThread(String name){
           super(name);
     }
     // 提供指定线程名、线程组的构造器
     public MyThread(ThreadGroup group , String name){
           super(group, name);
     }
     public void run(){
           for (int i = 0; i < 3 ; i++ ){
                System.out.println(getName() + " 线程的i变量" +  i);
           }
     }
}
public class ThreadGroupTest{
     public static void main(String[] args){
           // 获取主线程所在的线程组，这是所有线程默认的线程组
           ThreadGroup mainGroup =  Thread.currentThread().getThreadGroup();
           System.out.println("主线程组的名字："+ mainGroup.getName());
           System.out.println("主线程组是否是后台线程组："+ mainGroup.isDaemon());
           new MyThread("主线程组的线程").start();
           ThreadGroup tg = new ThreadGroup("新线程组");
           tg.setDaemon(true);
           System.out.println("tg线程组是否是后台线程组："+ tg.isDaemon());
           MyThread tt = new MyThread(tg , "tg组的线程甲");
           tt.start();
           new MyThread(tg , "tg组的线程乙").start();
     }
}
2 运行

主线程组的名字：main
主线程组是否是后台线程组：false
tg线程组是否是后台线程组：true
主线程组的线程 线程的i变量0
tg组的线程甲 线程的i变量0
tg组的线程甲 线程的i变量1
主线程组的线程 线程的i变量1
tg组的线程乙 线程的i变量0
tg组的线程乙 线程的i变量1
tg组的线程乙 线程的i变量2
主线程组的线程 线程的i变量2
tg组的线程甲 线程的i变量2
3 说明

首先获取主线程所属的线程组，并访问该线程组的相关属性，接着创建一个新线程组，并将该线程组设置为后台线程组。
